package com.gadberry.utility.algorithm.construct;

/**
 * 
 * @author Peter Lager
 *
 */
public enum FlowConstruct {
	IF (	"IF", 		1, 	Location.START),
	ELSE (	"ELSE", 	1, 	Location.INTER),
	ENDIF (	"ENDIF", 	1, 	Location.END),
	WHILE (	"WHILE", 	2, 	Location.START),
	WEND (	"WEND", 	2, 	Location.END),
	REPEAT ("REPEAT", 	3, 	Location.START),
	UNTIL (	"UNTIL", 	3, 	Location.END),
	OTHER (	"OTHER", 	0, 	Location.NONE); // This last one is for everything else.

	private static FlowConstruct[] tokens = null;

	private final String token;
	private final int group;
	private final Location position;

	private FlowConstruct(String token, int group, Location loc){
		this.token = token;
		this.group = group;
		this.position = loc;
	}

	/**
	 * Get an arrays of all the flow control constructs. Used when the statement is executed
	 * to determine which
	 * @return
	 */
	public static FlowConstruct[] getConstructs(){
		if(tokens == null)
			tokens = new FlowConstruct[]{ IF, ELSE, ENDIF, WHILE, WEND, REPEAT, UNTIL };
		return tokens;
	}

	/**
	 * Is this a start flow construct?
	 */
	public boolean isSTART(){
		return position == Location.START;
	}
	
	/**
	 * Is this an intermediate flow construct?
	 */
	public boolean isINTER(){
		return position == Location.INTER;
	}
	
	/**
	 * Is this an end flow construct?
	 */
	public boolean isEND(){
		return position == Location.END;
	}
	
	/**
	 * Determines whether the supplied flow construct is a valid end construct for this one.
	 * @param possibleEnd flow construct to test
	 * @return true if valid
	 */
	public boolean isMatchingStartFor(FlowConstruct possibleEnd){	
		if(group == possibleEnd.group && position.location < possibleEnd.position.location)
			return true;
		else
			return false;
	}
	
	/**
	 * Determines whether the supplied flow construct is a valid start construct for this one.
	 * @param possibleStart flow construct to test
	 * @return true if valid
	 */
	public boolean isMatchingEndFor(FlowConstruct possibleStart){	
		if(group == possibleStart.group && position.location > possibleStart.position.location)
			return true;
		else
			return false;
	}
	
	/**
	 * Get the text used to identify this construct in the algorithm.
	 * @return token text e.g. "IF", "REPEAT" etc.
	 */
	public String getToken() {
		return token;
	}

	/**
	 * Enumeration of the different construct types.
	 * 
	 * @author Peter Lager
	 *
	 */
	private enum Location {
		NONE(0), START(1), INTER(2), END(3);

		private final int location;
		
		private Location(int value){
			this.location = value;
		}
	}

}
